#include <sstream>
#define MAX_STRING_LEN 512
#define MAX_REPEAT_NUM 255
#define SEP << ' '

struct LOGIN_REQ
{
    enum {
        MSG_ID = 1024;
    };
    size_t account_len;
    char account[MAX_STRING_LEN];
    size_t password_len;
    char password[MAX_STRING_LEN];
    INT32 card;
    INT32 id;
    size_t roleid_num;
    INT32 roleid[MAX_REPEAT_NUM];
    const char* doc = "client LOGIN_MESSAGE_REQ";

    size_t Size() const
        {
            return account_len + password_len + sizeof(card) + sizeof(id) + roleid_num*sizeof(INT32);
        }
    
    std::string Describe() const
        {
            std::ostringstream outSs;
            outSs << "received LOGIN_REQ size:" SEP << Size() SEP
                  << "<account :string" SEP << account SEP << "len" SEP << account_len SEP
                  << "<password :string" SEP << password SEP << "len" SEP << password_len SEP
                  << "<card :int32" SEP << card SEP
                  << "<id :int32" SEP << id SEP
                  << "<roleid :int32" SEP << '{';
            for (int i = 0; i < roleid_num; ++i) {
                outSs << roleid[i];
                i + 1 < roleid_num ? outSs << ',' :;
            }
            outSs << '}';
            outSs << ">";
            return ousSs.str();
        }
};

typedef int (*encode_func) (void*, int, char* size_t);
typedef int (*decode_func) (void*, int, const char*, size_t);

#define MAX_MESSAGE_NUM 65535

encode_func encode_func_table[MAX_MESSAGE_NUM] = {0};
decode_func decode_func_table[MAX_MESSAGE_NUM] = {0};

int Encode(const void* obj, int msg_id, char* outBuf, size_t outBufLen) 
{
    encode_func func = encode_func_table[msg_id];
    return (*func)(obj, outBuf, outBufLen);
}

int Decode(void* obj, int msg_id, const char* inBuf, size_t inBufLen)
{
    decode_func func = decode_func_table[msg_id];
    return (*func)(obj, inBuf, inBufLen);
}

int DecodeLOGIN_REQ(void* pOut, const char* inBuf, size_t inBufLen)
{
    LOGIN_REQ *pOutStruct = (LOGIN_REQ*)(pOut);
    // Decode LOGIN_REQ account_len
    if (inBuf->DeSize(pOutStruct->account_len) == -1) {
        VLOG(ERROR, "LOGIN_REQ account_len error");
        return -1;
    }
    // Decode LOGIN_REQ string account
    if (inBuf->DeString(pOutStruct->account, pOutStruct->account_len, MAX_STRING_LEN) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ account :string len %d error",
             pOutStruct->account_len);
        return -1;
    }
    // Decode LOGIN_REQ password_len
    if (inBuf->DeSize(pOutStruct->password_len) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ password_len error");
        return -1;
    }
    // Decode LOGIN_REQ password string
    if (inBuf->DeString(pOutStruct->password, pOutStruct->password_len, MAX_STRING_LEN) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ password :string len %d error",
             pOutStruct->password_len);
        return -1;
    }
    if (inBuf->DeInt32(pOutStruct->card) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ card :int32 error");
        return -1;
    }
    if (inBuf->DeInt32(pOutStruct->id) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ card :int32 error");
        return -1;
    }
    if (inBuf->DeSize(pOutStruct->roleid_num) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ roleid num error");
        return -1;
    }
    if (inBuf->DeString(pOutStruct, pOutStruct->roleid_num, MAX_REPEAT_NUM) == -1) {
        VLOG(ERROR, "Decode LOGIN_REQ roleid :repeated %d :int32",
             pOutStruct->roleid_num);
        return -1;
    }
    return inBuf->Length();
}

void InstallDecodeFunctions()
{
    decode_func_table[LOGIN_REQ::MSG_ID] = DecodeLOGIN_REQ;
}
